package com.witmore.skyline.web.utils;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 地址解析工具类 AddressParserUtils
 * 逐级消费地址字符串（省 -> 市 -> 区），避免前缀被重复捕获。
 * 纯 Java、无外部依赖，适合快速本地解析。
 *
 * @author 豆子高
 */
@Slf4j
public class AddressParserUtils {

    private static final Logger logger = LoggerFactory.getLogger(AddressParserUtils.class);

    private static final Set<String> MUNICIPALITIES = new HashSet<>(
            Arrays.asList("北京市", "上海市", "天津市", "重庆市"));

    // 省级（包含 省 / 自治区 / 直辖市 / 特别行政区）
    private static final Pattern PROVINCE_PATTERN = Pattern.compile(
            "(.+?(省|自治区|特别行政区|市))");
    // 市级（包含 市 / 地区 / 自治州 / 区划中可能出现的“盟”）
    private static final Pattern CITY_PATTERN = Pattern.compile(
            "(.+?(市|地区|自治州|盟|自治县))");
    // 区级（区/县/旗/镇/乡/街道），这里尽量只匹配区级关键词
    private static final Pattern DISTRICT_PATTERN = Pattern.compile(
            "(.+?(市|区|县|旗|镇|乡|街道|街|村))");

    /**
     * 解析地址
     *
     * @param address 原始地址
     * @return AddressInfo 地址信息对象
     */
    public static AddressInfo parseAddress(String address) {
        logger.info("开始解析地址: {}", address);

        if (address == null || address.trim().isEmpty()) {
            logger.warn("输入地址为空或null");
            return new AddressInfo("", "", "", address);
        }

        String src = address.trim();
        String originalAddress = src;
        String province = "";
        String city = "";
        String district = "";

        try {
            // 1) 省级匹配（在原始字符串上匹配一次）
            Matcher pMatcher = PROVINCE_PATTERN.matcher(src);
            if (pMatcher.find()) {
                province = pMatcher.group(1);
                logger.debug("匹配到省级: {}", province);
                // 消费已匹配部分
                src = src.substring(pMatcher.end());
            } else {
                logger.debug("未匹配到省级信息");
            }

            // 处理直辖市：如果省是直辖市（北京市等），把市赋为省（但仍继续在剩余字符串里找区）
            if (!province.isEmpty() && MUNICIPALITIES.contains(province)) {
                city = province;
                logger.debug("识别为直辖市: {}", city);
            } else {
                // 2) 市级在剩余字符串中匹配
                Matcher cMatcher = CITY_PATTERN.matcher(src);
                if (cMatcher.find()) {
                    city = cMatcher.group(1);
                    logger.debug("匹配到市级: {}", city);
                    src = src.substring(cMatcher.end());
                } else {
                    logger.debug("未匹配到市级信息");
                }
            }

            // 3) 区级在剩余字符串中匹配
            Matcher dMatcher = DISTRICT_PATTERN.matcher(src);
            if (dMatcher.find()) {
                district = dMatcher.group(1);
                logger.debug("匹配到区级: {}", district);
                // src = src.substring(dMatcher.end()); // 可按需继续消费提取街道/门牌
            } else {
                logger.debug("未匹配到区级信息");
            }

            // 如果省没匹配但市匹配（例如省略省名的地址），尝试把市推到省位置（可选）
            // 注：这里不强制，但保留注释供你按需启用
            if (province.isEmpty() && !city.isEmpty()) {
                logger.debug("省为空但市不为空的情况: 市={}", city);
                // 例如 "深圳市南山区..."，可认为省为空，市=深圳市
            }

            AddressInfo result = new AddressInfo(
                    province == null ? "" : province,
                    city == null ? "" : city,
                    district == null ? "" : district,
                    originalAddress
            );

            logger.info("地址解析完成: {} -> {}", address, result);
            return result;

        } catch (Exception e) {
            logger.error("地址解析异常: {}", address, e);
            return new AddressInfo("", "", "", originalAddress);
        }
    }


    /**
     * 解析地址信息
     *
     * @param address     地址
     * @param businessName 名称
     * @return 地址解析结果
     */
    public static AddressParserUtils.AddressInfo parseAddress(String address, String businessName) {
        if (StringUtils.isBlank(address)) {
            log.debug("地址为空，跳过解析，名称: {}", businessName);
            return null;
        }

        try {
            AddressParserUtils.AddressInfo addressInfo = AddressParserUtils.parseAddress(address);
            log.info("地址解析成功，名称: {}, 地址: {}, 省: {}, 市: {}, 区: {}",
                    businessName, address,
                    addressInfo.getProvince(), addressInfo.getCity(), addressInfo.getDistrict());
            return addressInfo;
        } catch (Exception e) {
            log.error("地址解析失败，名称: {}, 地址: {}", businessName, address, e);
            return null;
        }
    }

    // 简单测试
    public static void main(String[] args) {
        List<String> tests = Arrays.asList(
                "浙江省绍兴市诸暨市店口镇瓦水库东南约335米",
                "浙江省绍兴市诸暨市闸屋东南约691米",
                "浙江省绍兴市诸暨市金戈西南约83米"
        );

        for (String t : tests) {
            AddressInfo result = parseAddress(t);
            System.out.println(t + " => " + result);
        }
    }

    /**
     * 地址信息封装类
     * 用于封装地址解析结果，便于其他模块使用
     */
    @Setter
    @Getter
    public static class AddressInfo {
        /**
         * 省份
         */
        private String province;
        /**
         * 城市
         */
        private String city;
        /**
         * 区县
         */
        private String district;
        /**
         * 原始地址
         */
        private String originalAddress;

        public AddressInfo() {
        }

        public AddressInfo(String province, String city, String district, String originalAddress) {
            this.province = province;
            this.city = city;
            this.district = district;
            this.originalAddress = originalAddress;
        }

        /**
         * 获取完整的省市区信息
         *
         * @return 省市区拼接字符串
         */
        public String getFullRegion() {
            StringBuilder sb = new StringBuilder();
            if (province != null && !province.isEmpty()) {
                sb.append(province);
            }
            if (city != null && !city.isEmpty()) {
                sb.append(city);
            }
            if (district != null && !district.isEmpty()) {
                sb.append(district);
            }
            return sb.toString();
        }

        /**
         * 检查地址解析是否成功
         *
         * @return 如果至少解析出省或市信息则返回true
         */
        public boolean isValid() {
            return (province != null && !province.isEmpty()) ||
                    (city != null && !city.isEmpty());
        }


        @Override
        public String toString() {
            return "AddressInfo{" +
                    "province='" + province + '\'' +
                    ", city='" + city + '\'' +
                    ", district='" + district + '\'' +
                    ", originalAddress='" + originalAddress + '\'' +
                    ", fullRegion='" + getFullRegion() + '\'' +
                    ", isValid=" + isValid() +
                    '}';
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            AddressInfo that = (AddressInfo) o;
            return Objects.equals(province, that.province) &&
                    Objects.equals(city, that.city) &&
                    Objects.equals(district, that.district) &&
                    Objects.equals(originalAddress, that.originalAddress);
        }

        @Override
        public int hashCode() {
            return Objects.hash(province, city, district, originalAddress);
        }
    }
}
